home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 045 (1988-02-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 045 (1988-02-15)(Ossowski, Stefan)(DE)(PD).adf / Iff2Pcs / Source / popmenu.c < prev    next >
C/C++ Source or Header  |  1988-01-20  |  9KB  |  255 lines

  1. /* PopMenu code by Helene (Lee) Taran, from the Splines program 
  2. ** from Fish disk 97 (which replace disk 57).
  3. */
  4.  
  5. #include <functions.h>
  6. #include "popmenu.h"
  7.  
  8. /* For some reason, someone forgot to include NewLayerInfo() in functions.h...
  9. */
  10. struct Layer_Info *NewLayerInfo();
  11. struct Layer_Info *PopUp_LayerInfo;
  12. struct Font *menufont;
  13.  
  14. /* User should call Init_MenuPackage() before trying to pop up any
  15.  * menus. Will return TRUE if the package has been initialized correctly.
  16.  * Do not attempt to use this package if this initialization routine 
  17.  * returns FALSE.
  18.  */
  19. int Init_MenuPackage()
  20.   static struct TextAttr MenuFont = {(UBYTE *)"topaz.font",8,0,0};
  21.  
  22.   if (!(menufont = OpenFont(&MenuFont))) return (0);
  23.   if (!(PopUp_LayerInfo = (struct Layer_Info *)NewLayerInfo())) return (0);
  24.   return(1);
  25. }
  26.  
  27. /* The user should call Close_MenuPackage before exiting their program
  28.  * to ensure that the menu package releases any memory that it
  29.  * has allocated for its own use. 
  30.  */
  31. Close_MenuPackage()
  32. {
  33.   CloseFont(menufont);
  34.   if (PopUp_LayerInfo != NULL) DisposeLayerInfo(PopUp_LayerInfo);
  35. }
  36.  
  37. int Init_PopUp_Menu (menu)
  38. struct PopUp_Menu *menu;
  39. {
  40.   struct PopUp_Item *item;
  41.   int longest = 0;
  42.   int total_height = 0;
  43.   int i;
  44.  
  45.   if (menu == NULL) return(0);
  46.   item = menu->first_item;
  47.   while (item != NULL) {
  48.     /* note: bad things may happen if you allocate an empty string for
  49.      * your item text.
  50.      */
  51.      item->width = MAX(item->width, FONT_WIDTH * strlen(item->text));
  52.      item->left  = MAX(0,item->left);
  53.      longest = MAX(longest, (item->width + item->left));
  54.      item->height = MAX(item->height, FONT_HEIGHT);
  55.      item->top = MAX(0,item->top);
  56.      total_height += (item->height + item->top);
  57.     /* re-initialize item-top to be the top relative to the menu top */
  58.      item->top = (total_height  - item->height); 
  59.      item = item->next;
  60.   }
  61.   menu->height = total_height+1;
  62.   menu->width  = MAX(menu->width, longest);
  63.   
  64.   /* initialize a bitmap the same size as the required menu image  */
  65.   /* initialize a raster port to facillitate drawing into the bitmap */
  66.   InitBitMap(&(menu->bitmap),
  67.              (long)menu->depth,(long)menu->width,(long)menu->height);
  68.   InitRastPort(&(menu->rp));  
  69.   SetFont(&(menu->rp),menufont);
  70.   for (i = 0; i < menu->depth; i++) 
  71.     if (!(menu->bitmap.Planes[i] = (PLANEPTR) AllocRaster((long)menu->width, (long)menu->height))) {
  72.       Dispose_PopUp(menu); return(0);
  73.     }
  74.   menu->rp.BitMap = &(menu->bitmap); 
  75.   menu->cr.BitMap = &(menu->bitmap);
  76.  
  77.   /* draw the menu outline and background color into its own bitmap */
  78.   SetDrMd(&(menu->rp),JAM1);
  79.   SetAPen(&(menu->rp),(long)menu->area_color);
  80.   SetOPen(&(menu->rp),(long)menu->outline_color);
  81.  
  82.   RectFill(&(menu->rp),0L,0L,menu->width-1L,menu->height-1L);  
  83.   BNDRYOFF(&(menu->rp));  /* turn off the raster port outlining */
  84.  
  85.   item = menu->first_item;  
  86.    
  87.   /* Now, draw each menu item */
  88.   while (item != NULL) {
  89.      SetAPen(&(menu->rp),(long)item->color);
  90.      Move(&(menu->rp),(long)item->left,(long)item->top + FONT_BASELINE);
  91.      Text(&(menu->rp),item->text,(long)strlen(item->text));
  92.      item = item->next;
  93.   }
  94.   return(1);
  95. }
  96.  
  97. /* SelectItem : activates the item located at <x,y>. Assumes the <menu>
  98.  * is currently active and thus, menu->left and menu->top should represent
  99.  * the menu's current top,left corner.  If there is an item located
  100.  * at <x,y> within the menu, then it is made 'active' ...this means
  101.  * that the item becomes menu->active_item and is highlighted. The
  102.  * old menu->active_item, if any, is deselected. Note: if you're using
  103.  * a GIMMEZEROZERO window you'll have to fiddle with the x,y coordinates.
  104.  */
  105. SelectItem(menu,Window)
  106. struct PopUp_Menu *menu;
  107. struct Window *Window;
  108. {  struct PopUp_Item *item;
  109.  
  110.    SHORT x = Window->MouseX + Window->LeftEdge;
  111.    SHORT y = Window->MouseY + Window->TopEdge;
  112.   
  113.    item = menu->first_item;
  114.    x -= menu->left;  y -= menu->top;
  115.    if ((x >= 0) && (x < menu->width) && (y >= 0) && (y < menu->height))
  116.       while (item != NULL) { 
  117.          if ((y >= item->top -1) && (y < item->top -1 + item->height))
  118.              break; /* we found an active item {yeah yeah...bad style, i know...} */
  119.           else item = item->next;
  120.          }
  121.    else item = NULL;    /* mouse isn't on menu */
  122.  
  123.    if (menu->active_item != item) {     /* deselect previously active item */
  124.       ComplementItem(menu,menu->active_item,Window);
  125.       ComplementItem(menu,item,Window);
  126.    }
  127.    menu->active_item = item;
  128. }
  129.        
  130.         
  131.    
  132.          
  133. /* ComplementItem : complements the given menu item area.  Assumes that
  134.  * the <menu> is currently being displayed and thus,the current menu->left
  135.  * and menu->top represent the current coordinates of the menu's top,left
  136.  * corner.  Assumes the <item> is  an popup_item that belongs to <menu>
  137.  * and that its left/top offsets have been initialized.
  138.  */
  139. ComplementItem(menu,item,Window)
  140. struct PopUp_Menu *menu;
  141. struct PopUp_Item *item;
  142. struct Window *Window;
  143. {  BYTE old_mode = Window->WScreen->RastPort.DrawMode;
  144.  
  145.    if (item == NULL) return;  /* do nothing */
  146.    SetDrMd(&(Window->WScreen->RastPort), COMPLEMENT);
  147.    RectFill(&(Window->WScreen->RastPort), (long)menu->left,
  148.                            menu->top +  item->top - 1L,
  149.                            menu->left + menu->width -1L,
  150.                            menu->top +  item->top + item->height - 2L);
  151.    SetDrMd(&(Window->WScreen->RastPort), (long)old_mode);
  152. }
  153.  
  154. /* PopUp : this is one of those 'do everything' type of functions. It
  155.  * displays the <menu> in the window  given its upper left hand 
  156.  * coordinates <left,top>.  It tracks the user's mouse movements,
  157.  * highlighting the currently active item until the user deselects
  158.  * the menu by releasing the mouse's select button, at which time,
  159.  * this function will remove the menu from the display. Returns the
  160.  * selection_id of the item that was active when the user releases
  161.  * the select button. Returns 0 if nothing was selected.
  162.  * Assumes that the <menu> has been initialized by a call to 
  163.  * Init_PopUp_Menu and that the user has requested ReportMouse for the
  164.  * Window in question (ReportMouse makes sure that the Window's MouseX and
  165.  * MouseY coordinates are kept up to date).
  166.  */
  167. int PopUp(menu,Window)
  168. struct PopUp_Menu *menu;
  169. struct Window *Window;
  170. { ULONG oldflags;
  171.   SHORT left, top;
  172.  
  173.   left = Window->MouseX;
  174.   top = Window->MouseY;
  175.   if (!Inside_Window(left,top,Window)) return(OUTSIDE_WINDOW);
  176.  
  177.   if ((menu->width <= Window->Width) && (left + menu->width > Window->Width))
  178.      left += Window->Width - (left + menu->width);
  179.  
  180.   if ((menu->height <= Window->Height) && (top + menu->height > Window->Height))
  181.      top += Window->Height - (top + menu->height);
  182.  
  183.   LockLayers(PopUp_LayerInfo);
  184.   /* SwapBits...() requires that the clipping rectangle's bounds are given
  185.    * with respect to the screen's 0,0 coordinate but mouse movements
  186.    * are reported to the Window and are given in terms of the window's
  187.    * coordinate system so...sLeft and sTop represent the adjustment of
  188.    * the Window's coordinates to match the screen's coordinates.
  189.    * Note: if you're using a GIMMEZEROZERO window, you'll have to muck
  190.    * with the left,top coordinates to get the complementing to work.
  191.    */
  192.   left = (left + Window->LeftEdge) & 0xfff0;
  193.   top =  top + Window->TopEdge;
  194.  
  195.   menu->cr.bounds.MinX = left;    
  196.   menu->cr.bounds.MinY = top;
  197.   menu->cr.bounds.MaxX = left + menu->width -1;
  198.   menu->cr.bounds.MaxY = top + menu->height -1;
  199.  
  200.   SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
  201.  
  202.   menu->left = left;
  203.   menu->top =  top;
  204.   SelectItem(menu,Window);  
  205. /*
  206. **oldflags = Window->IDCMPFlags;
  207. **ModifyIDCMP(Window,oldflags | MOUSEMOVE);
  208. */
  209.  
  210.   ReportMouse (TRUE, Window);  /* Start telling us about mouse loc */    
  211.  
  212.   while (1)  /* wait for the user to select an item and deselect the menu */
  213.      { struct IntuiMessage msg, *message;
  214.        int MouseMoved = FALSE;
  215.  
  216.        Wait(1L << Window->UserPort->mp_SigBit);
  217.        while (message = (struct IntuiMessage *)GetMsg(Window->UserPort)) { 
  218.             msg = *message;         /* make a backup copy of message */
  219.             ReplyMsg(message);      /* reply immediately to prevent deadlock */
  220.             if (msg.Class == MOUSEMOVE)
  221.                /* just keep track of the fact that the mouse moved */
  222.             MouseMoved = TRUE; 
  223.             else if ((msg.Class == MOUSEBUTTONS) && (msg.Code == menu->deactivate)) {
  224.                 /* user has deselected the menu */
  225.                     ReportMouse (FALSE, Window);  
  226.                     SelectItem(menu,Window);
  227.                     SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
  228.                     UnlockLayers(PopUp_LayerInfo); 
  229.                     if (menu->active_item != NULL)
  230.                        return(menu->active_item->selection_id);
  231.                     else return(NOITEM_SELECTED);
  232.                 } /* end of deselection routine */
  233.             }
  234.        /* 
  235.         * at this point the message queue should be empty so the mouse
  236.         * has stopped for the moment.
  237.         */
  238.           if (MouseMoved) SelectItem(menu,Window);
  239.       } 
  240. }
  241.  
  242. Dispose_PopUp(menu)
  243. struct PopUp_Menu *menu;
  244. {
  245.   int i;
  246.   for (i = 0; i < menu->depth; i++)
  247.     if (menu->bitmap.Planes[i] != NULL)
  248.        FreeRaster(menu->bitmap.Planes[i], (long)menu->width, (long)menu->height);
  249. }
  250.            
  251.  
  252.      
  253.      
  254.